函式
package main
import "fmt"
func main() {
sum := Add(5, 3)
fmt.Println("5 + 3 =", sum) // 5 + 3 = 8
_, s := Add4(5, 3)
fmt.Println(s) // 5 + 3 = 8
sum2 := Add5(1, 2, 3, 4)
fmt.Println(sum2) // 10
}
// 單回傳值
func Add(a int, b int) int {
return a + b
}
// 如果參數型別一樣,可以只宣告一次
func Add2(a, b int) int {
return a + b
}
// 如果回傳值有宣告名稱,可以不用 return
func Add3(a, b int) (sum int) {
sum = a + b
return
}
// 多回傳值
func Add4(a, b int) (int, string) {
s := fmt.Sprintf("%d + %d = %d", a, b, a+b)
return a + b, s
}
// 不定長度函數
func Add5(nums ...int) int {
sum := 0
for _, val := range nums {
sum += val
}
return sum
}
匿名函式
package main
import "fmt"
func main() {
add := func(a, b int) int {
return a + b
}
fmt.Println(add(5, 3)) // 8
}
defer 後進先出 (LIFO, Last In First Out)
package main
import "fmt"
func main() {
defer fmt.Println("最後執行")
fmt.Println("最先執行")
for i := 0; i < 5; i++ {
defer fmt.Println(i)
}
fmt.Println("main func 結束執行")
}
// 最先執行
// main func 結束執行
// 4
// 3
// 2
// 1
// 0
// 最後執行
通常使用時機這個函式執行完後,對其資源需做釋放時,會使用 defer
package main
import (
"fmt"
"os"
)
func main() {
// 打開檔案
file, err := os.Open(fileName)
if err != nil {
fmt.Println("無法打開檔案:", err)
return
}
defer file.Close() // 函數執行完畢後釋放資源
// 後續可以做讀取檔案內容操作
}
error
package main
import (
"errors"
"fmt"
)
func main() {
result, err := divide(8, 0)
if err != nil {
fmt.Println("error: ", err)
} else {
fmt.Println(result)
}
}
// 可以自行拋出 error,因此在設計函數時可以一併考慮是否該設計進去
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除數不能為零")
}
return a / b, nil
}
error 建議一定要處理或往上層拋,Go 其中一個設計理念就是希望開發者能對每一個 error 作處理,所以可以發現 Go 是沒有 try catch 的關鍵字。(這裡指的 error,是可預期的錯誤
這也變相要求開發者必須清楚知道哪個流程會拋出錯誤,我覺得這是好事,所以我是支持這個設計
(呃,社群好像反對或支持這個設計的聲音都有,所以也不能排除未來可能會有 try catch
有些錯誤不是在編譯或是程式設計中可預期的錯誤,屬於執行錯誤 (runtime error) 就會拋出 panic
package main
import "fmt"
func main() {
fmt.Println("執行")
// 觸發 panic
panic("panicccc")
// fmt.Println("不會執行")
}
發生 panic 時已經算是嚴重的錯誤,通常就不處理了。理想上如果能預期錯誤的話,就應該要被包裝成 error,程式設計師再針對此錯誤做特定處理。
但是這也不是絕對的,像是一個服務其中有個功能有問題,但是不能因為這個功能導致整個服務異常時,可以使用 recover
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recover from: ", r)
}
}()
fmt.Println("執行")
// 觸發 panic
panic("panicccc")
// fmt.Println("不會執行")
}
error handle 是一個重要且值得討論的議題,需要謹慎面對,但是這裡就先不展開討論。
只有天真的程式設計師會相信讀寫不會失敗
方法
package main
import "fmt"
type Rectangle struct {
W float64
H float64
}
func (r Rectangle) Area() float64 {
return r.W * r.H
}
func (r Rectangle) Perimeter() float64 {
return 2*r.W + 2*r.H
}
func main() {
rect := Rectangle{W: 5, H: 3}
area := rect.Area()
perimeter := rect.Perimeter()
fmt.Println(area)
fmt.Println(perimeter)
}